还没有笔记
选中页面文字后点击「高亮」按钮添加
COMS W3157
Borowski 博士
协议是通信双方之间关于如何进行通信的约定。
不同的协议是针对不同的情况而构建的。
在互联网上,我们通常使用 TCP/IP 以及各种协议,例如 HTTP、FTP、SMTP、POP 等。
服务是某一层向其上层提供的一组原语(操作)。
相比之下,协议是管理层内对等实体交换的数据包或消息格式和含义的一组规则。
实体使用协议来实现其服务定义。

基于国际标准化组织(ISO)提出的一项建议,作为各种层中使用的协议国际标准化的第一步(Day 和 Zimmermann,1983)。
它在 1995 年进行了修订(Day,1995)。
参考模型,因为它处理连接开放系统。大学
OSI 模型有七层。应用于这七层所遵循的原则可以简要概括如下:
层
交换单位名称

传输控制协议 / 互联网协议 TCP/IP 有点过于复杂,无法归类到 OSI 模型的单个层中。
它是一系列在不同层上工作的工具,并被许多其他应用层协议使用。
例如,HTTP 和 DNS 依赖 TCP/IP 才能正常工作。
大多数当前的网络都使用 TCP/IP。
DNS,即域名系统,是一项基本的互联网服务,它将人类可读的域名(如 google.com)转换为计算机用于定位网站和其他在线资源的数字 IP 地址
像 OSI 模型一样分层组织,但只有 4 层而不是 7 层。
| OSI | |
| :--- | :--- |
| 7 | 应用 |
| 6 | 表示 |
| 5 | 会话 |
| 4 | 传输 |
| 3 | 网络 |
| 2 | 数据链路 |
| 1 | 物理 |
| | |
TCP/IP


套接字是类似于电话的通信通道。它完全是关于两个端点之间的通信。

套接字由套接字描述符标识
int socket(int domain, int type, int protocol);
| 地址族 | | 我们将在本课程中使用 AF_INET。 | |
| :--- | :--- | :--- | :--- |
| 名称 | 目的 | | 手册页 |
| AF_UNIX, AF_LOCAL | 本地通信 | | unix(7) |
| AF_INET | IPv4 互联网协议 | | ip(7) |
| AF_INET6 | IPv6 互联网协议 | | ipv6(7) |
| AF_IPX | IPX - Novell 协议 | | |
| AF_NETLINK | 内核用户界面设备 | | netlink(7) |
| AF_X25 | ITU-T X.25 / ISO-8208 协议 | | x25(7) |
| AF_AX25 | 业余无线电 AX.25 协议 | | |
| AF_ATMPVC | 原始 ATM PVC 访问 | | |
| AF_APPLETALK | AppleTalk | | ddp(7) |
| AF_PACKET | 低级别数据包接口 | | packet(7) |
| AF_ALG | 内核加密 API 接口 | | |
socket(AF_INET, SOCK_DGRAM, 0)
socket(AF_INET, SOCK_STREAM, 0)
套接字标识:IP 地址 + 端口号



本幻灯片组的其余部分演示了回显客户端和回显服务器之间使用基于 TCP 的套接字进行通信。
服务器会回显从客户端收到的任何字符串。
哥伦比亚

int socket(int domain, int type, int protocol);
socket() 创建一个通信端点并返回一个文件描述符,该文件描述符引用该端点。成功调用返回的文件描述符将是进程中当前未打开的最低编号文件描述符。
AF_INET 用于 IPv4
AF_INET6 用于 IPv6
SOCK_STREAM: 可靠字节流 (TCP)
SOCK_DGRAM: 面向消息服务 (UDP)
UNSPEC: 未指定
(AF_INET 和 SOCK_STREAM 已经暗示 TCP,"0" 设置协议)
sockfd = socket(AF_INET, SOCK_STREAM, 0);
```
int serversock;
serversock = socket(AF_INET, SOCK_STREAM, 0);
```
哥伦比亚
大学
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
当使用 socket(2) 创建套接字时,它存在于一个命名空间(地址族)中,但没有为其分配地址。 bind() 将 addr 指定的地址分配给由文件描述符 sockfd 引用的套接字。 addrlen 指定由 addr 指向的地址结构的大小(以字节为单位)。传统上,此操作称为“为套接字命名”。
```
int serversock;
serversock = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in echoserver;
memset(&echoserver, 0, sizeof(echoserver));
echoserver.sin_family = AF_INET;
echoserver.sin_addr.s_addr = htonl(INADDR_ANY);
echoserver.sin_port = htons(atoi(argv[1]));
bind(serversock, (struct sockaddr *) &echoserver,
sizeof(echoserver));
```
```
/ Internet address /
struct in_addr {
uint32_t s_addr; / address in network byte order /
};
struct sockaddr_in {
sa_family_t sin_family; / unsigned short, address family: AF_INET /
in_port_t sin_port; / unsigned short, port in network byte order /
struct in_addr sin_addr; / internet address /
char sin_zero[8]; / Not used /
};
struct sockaddr {
sa_family_t sa_family; / unsigned short /
char sa_data[14]; / blob /
};
\begin{tabular}{|l|l|l|l|l|l|}
\hline \multirow{5}{*}{\begin{tabular}{l}
sockaddr_in \\
sockaddr
\end{tabular}} & sa_family & \multicolumn{4}{|c|}{sa_data} \\
\hline & Family & \multicolumn{4}{|c|}{Blob (14 bytes)} \\
\hline & 2 bytes & 2 bytes & 4 bytes & & 8 bytes \\
\hline & Family & Port & Internet address & & Unused \\
\hline & sin_family & sin_port & sin_addr & & sin_zero \\
\hline
\end{tabular}
\begin{tabular}{|l|}
\hline Format of struct sockaddr \\
depends on specified \\
domain. \\
To use a single bind interface \\
for all domains, we use the \\
most general format - struct \\
sockaddr. \\
A domain specific format can \\
be typecast to struct \\
sockaddr when binding.
\end{tabular}
Do "man sockaddr" to see all the specific types.
```
为了连接到远程计算机并使用套接字,我们需要使用其地址。
LINUX 是小端序,但 TCP/IP 使用大端序字节排序。
对于小端序,最低有效字节(“小端”)存储在最低内存地址处。
对于大端序,最低有效字节(“小端”)存储在最高内存地址处。
大端序

小端序

C 语言中用于确定系统字节序的简单代码。
x 是 int 类型,所以 x=1 会根据你的架构存储如下:
小端
| 字节 | 地址 |
| :---: | :---: |
| 00000000 | 1003 |
| 00000000 | 1002 |
| 00000000 | 1001 |
| 00000001 | 1000 |
大端
| 字节 | 地址 |
| :---: | :---: |
| 00000001 | 1003 |
| 00000000 | 1002 |
| 00000000 | 1001 |
| 00000000 | 1000 |
TCP/IP 的转换函数:
```
#include
uint32_t htonl(uint32_t hostlong);
uint16_t htons(uint16_t hostshort);
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);
```
哥伦比亚

int listen(int sockfd, int backlog);
许多客户端请求可能会到达服务器。
listen() 将由 sockfd 引用的套接字标记为被动套接字,即一个将用于使用 accept() 接受传入连接请求的套接字。
成功时返回 0,错误时返回 -1。
listen() 是非阻塞的;它立即返回。
```
#define MAXPENDING 5
int serversock;
serversock = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in echoserver;
memset(&echoserver, 0, sizeof(echoserver));
echoserver.sin_family = AF_INET;
echoserver.sin_addr.s_addr = htonl(INADDR_ANY);
echoserver.sin_port = htons(atoi(argv[1]));
bind(serversock, (struct sockaddr *) &echoserver,
sizeof(echoserver));
listen(serversock, MAXPENDING);
```
哥伦比亚

```
int accept(int sockfd, struct sockaddr *addr,
socketlen_t *addrlen);
```
现在服务器所能做的就是等待。
它等待连接请求的到来。
它会阻塞直到请求到来,然后接受新请求。
成功时返回接受的套接字的文件描述符,错误时返回 -1。
```
#define MAXPENDING 5
int clientsock, serversock;
serversock = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in echoclient, echoserver;
memset(&echoserver, 0, sizeof(echoserver));
echoserver.sin_family = AF_INET;
echoserver.sin_addr.s_addr = htonl(INADDR_ANY);
echoserver.sin_port = htons(atoi(argv[1]));
bind(serversock, (struct sockaddr *) &echoserver,
sizeof (echóserver));
listen(serversock, MAXPENDING);
clientsock = accept(serversock,
(struct sockaddr *) &echoclient,
sizeof(echoclient));
```
哥伦比亚

int socket(int domain, int type, int protocol);
socket() 创建一个通信端点并返回一个文件描述符,该文件描述符引用该端点。成功调用返回的文件描述符将是进程中当前未打开的最低编号文件描述符。
AF_INET 用于 IPv4
AF_INET6 用于 IPv6
SOCK_STREAM: 可靠字节流 (TCP)
SOCK_DGRAM: 面向消息服务 (UDP)
UNSPEC: 未指定
(AF_INET 和 SOCK_STREAM 已经暗示 TCP,"0" 设置协议)
sockfd = socket(AF_INET, SOCK_STREAM, 0);
```
int clientsock;
clientsock = socket(AF_INET, SOCK_STREAM, O);
```
哥伦比亚

```
int connect(int sockfd, const struct sockaddr *addr,
socklen_t addrlen);
```
connect() 系统调用将由文件描述符 sockfd 引用的套接字连接到由 addr 指定的地址。 addr 中的地址格式由套接字 sockfd 的地址空间决定。
成功时返回 0,错误时返回 -1。
注意客户端不需要调用 bind()。
```
int clientsock;
clientsock = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in echoserver;
memset(&echoserver, 0, sizeof(echoserver));
echoserver.sin_family = AF_INET;
echoserver.sin_addr.s_addr = inet_addr(argv[1]);
echoserver.sin_port = htons(atoi(argv[2]));
connect(clientsock, (struct sockaddr *) &echoserver,
sizeof(echoserver));
```
哥伦比亚

```
ssize_t send(int sockfd, const void *buf, size_t len,
int flags);
```
五个不同的系统调用用于发送数据:send、sendto、sendmsg、write 和 writev
在本课程中,我们将使用 send,它通常与连接套接字一起使用。
send() 和 write() 之间唯一的区别在于标志的存在。当零标志参数时,send() 通常等价于 write()。
成功时返回发送的字节数,错误时返回 -1。
```
#define BUFSIZE 32
int clientsock;
clientsock = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in echoserver;
memset(&echoserver, 0, sizeof(echoserver));
echoserver.sin_family = AF_INET;
echoserver.sin_addr.s_addr = inet_addr(argv[1]);
echoserver.sin_port = htons(atoi(argv[2]));
connect(clientsock, (struct sockaddr *)&echoserver,
sizeof(echoserver));
char buffer[BUFSIZE];
unsigned int len = strlen(argv[3]);
// Send '\0' too.
send(clientsock, argv[3], len + 1, 0);
```
```
ssize_t recv(int sockfd, void *buf, size_t len,
int flags);
```
五个不同的系统调用用于接收数据:recv、recvfrom、recvmsg、read 和 readv
在本课程中,我们将使用 recv,它通常与连接套接字一起使用。
recv() 和 read() 之间唯一的区别在于标志的存在。当零标志参数时,recv() 通常等价于 read()。
成功时返回接收的字节数,错误时返回 -1。
哥伦比亚大学
```
#define MAXPENDING 5
#define BUFSIZE 32
int clientsock, serversock;
serversock = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in echōclient, echoserver;
memset(&echoservier, 0, sizeof(echoserver));
echoserver.sin_family = AF_INET;
echoserver.sin_addr.s_addr = htonl(INADDR ANY);
echoserver.sin_port =-htons(atoi(argv[1]));
bind(serversock), (struct sockaddr *)&echoserver,
sizeof(echoserver));
listen (serversock, MAXPENDING) ;
clientsock = accept(serversock,
(struct sockaddr *) &echoclient,
sizeof(echoclient));
char buffer[BUFSIZE];
ssize_t num_recv = recv(clientsock, buffer, BUFSIZE, 0);
```
哥伦比亚

```
ssize_t send(int sockfd, const void *buf, size_t len,
int flags);
```
五个不同的系统调用用于发送数据:send、sendto、sendmsg、write 和 writev
在本课程中,我们将使用 send,它通常与连接套接字一起使用。
send() 和 write() 之间唯一的区别在于标志的存在。当零标志参数时,send() 通常等价于 write()。
成功时返回发送的字节数,错误时返回 -1。
哥伦比亚

```
#define MAXPENDING 5
#define BUFSIZE 32
int clientsock, serversock;
serversock = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in echōclient, echoserver;
memset(&echoserver, 0, sizeof(echoserver));
echoserver.sin_family = AF_INET;
echoserver.sin_addr.s_addr = htonl(INADDR ANY);
echoserver.sin_port =-htons(atoi(argv[1]));
bind(serversock, (struct sockaddr *) &echoserver,
sizeof(echoserver));
listen(serversock, MAXPENDING);
clientsock = accept(serversock,
(struct sockaddr *) &echoclient,
sizeof(echoclient));
char buffer[BUFSIZE];
ssize_t num_recv = recv(clientsock, buffer, BUFSIZE, 0);
send(clientsock, buffer, num_recv, 0);
```
```
#define BUFSIZE 32
int clientsock;
clientsock = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in echoserver;
memset(&echoserver, 0, sizeof(echoserver));
echoserver.sin_family = AF_INET;
echoserver.sin_addr.s_addr = inet_addr(argv[1]);
echoserver.sin_port = htons(atoi(argv[2]));
connect(clientsock, (struct sockaddr *)&echoserver,
sizeof(echoserver));
char buffer[BUFSIZE];
unsigned int len = strlen(argv[3]);
// Send '\0' too.
send(sock, argv[3], len + 1, 0);
ssize_t num_recv = recv(sock, buffer, BUFSIZE, 0);
// len + 1 should equal num_recv
```
哥伦比亚

int close(int fd);
close() 关闭一个文件描述符,使其不再引用任何文件,并且可以重用。
成功时返回 0,错误时返回 -1。
```
#define BUFSIZE 32
int clientsock;
clientsock = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in echoserver;
memset(&echoserver, 0, sizeof(echoserver));
echoserver.sin_family = AF_INET;
echoserver.sin_addr.s_addr = inet_addr(argv[1]);
echoserver.sin_port = htons(atoi(argv[2]));
connect(clientsock, (struct sockaddr *)&echoserver,
sizeof(echoserver));
char buffer[BUFSIZE];
unsigned int len = strlen(argv[3]);
// Send '\0' too.
send(sock, argv[3], len + 1, 0);
ssize_t num_recv = recv(sock, buffer, BUFSIZE, 0);
// len + 1 should equal num_recv
close(clientsock) ;
```
```
#define MAXPENDING 5
#define BUFSIZE 32
int clientsock, serversock;
serversock = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in echōclient, echoserver;
memset(&echoserver, 0, sizeof(echoserver));
echoserver.sin_family = AF_INET;
echoserver.sin_addr.s_addr = htonl(INADDR ANY);
echoserver.sin_port =-htons(atoi(argv[1]));
bind(serversock, (struct sockaddr *) &echoserver,
sizeof(echoserver));
listen(serversock, MAXPENDING);
clientsock = accept(serversock,
(struct sockaddr *) &echoclient,
sizeof(echoclient));
char buffer[BUFSIZE];
ssize_t num_recv = recv(clientsock, buffer, BUFSIZE, 0);
send(clientsock, buffer, num_recv, 0);
close(clientsock) ;
close(serversock);
```